package com.whl215.customview.mint

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.view.MotionEvent
import android.view.VelocityTracker
import android.view.View
import android.view.ViewConfiguration
import android.widget.Scroller
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import java.lang.RuntimeException
import java.math.RoundingMode


/**
仿薄荷健康 可滑动的尺子
尺子内容全部绘制
 */
class RulerView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {
    //---------------------------- 数据相关 ----------------------------
    var mRangeStart = 0
    var mRangeEnd = 100000
    var mScale = 1f //分度值
    private var mCountLine = 0 //根据数据边界 和  分度值计算 一共有多少刻度
    private var mValue: Float = 0f//当前刻度值

    //---------------------------- 绘制相关 ----------------------------
    private val mPaint: Paint = Paint().apply {
        color = Color.parseColor("#d9dde2")
        isAntiAlias = true
    }
    private val mRect = Rect()
    private val mSLineColor: Int
    private val mSLineWidth: Int
    private var mSLineHeight: Int = 0
    private val mLLineColor: Int
    private val mLLineWidth: Int
    private var mLLineHeight: Int = 0
    private var mLineSpace = 0
    private val mTextColor: Int
    private val mTextSize: Float
    private var mTextSpace = 0
    private val mBLLineWidth: Int

    //---------------------------- 滑动相关 ----------------------------
    private val mScroller = Scroller(context)
    private val mTouchSlop: Int
    private val mMaximumVelocity: Float
    private val mMinimumVelocity: Int
    private var mLastX = 0f
    private val mVelocityTracker: VelocityTracker by lazy { VelocityTracker.obtain() }

    //内容宽度 == 能够滑动的距离
    private var mContentWidth = 0

    //view 开始绘制的X坐标
    private var mStartDrawX = 0

    //是否开启自动定位
    private var mAutoPosition = false

    var onValueChangeListener: OnValueChangeListener? = null

    init {
        isClickable = true
        isFocusable = true

        val configuration = ViewConfiguration.get(context)
        mTouchSlop = configuration.scaledPagingTouchSlop
        mMaximumVelocity = configuration.scaledMaximumFlingVelocity.toFloat()
        mMinimumVelocity = configuration.scaledMinimumFlingVelocity

        mLineSpace = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, 8f,
            context.resources.displayMetrics
        ).toInt()
        mTextSpace = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, 8f,
            context.resources.displayMetrics
        ).toInt()


        mSLineColor = Color.parseColor("#d9dde2")
        mSLineWidth = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, 1f,
            context.resources.displayMetrics
        ).toInt()

        mLLineWidth = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, 2f,
            context.resources.displayMetrics
        ).toInt()

        mBLLineWidth = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP, 2f,
            context.resources.displayMetrics
        ).toInt()
        mLLineColor = Color.parseColor("#a9adbb")

        mTextColor = Color.parseColor("#a8acb9")
        mTextSize = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_SP, 16f,
            context.resources.displayMetrics
        )
    }

    /**
     * 测量
     */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        val height = measuredHeight
        val width = measuredWidth
        mStartDrawX = width / 2
        mCountLine = ((mRangeEnd - mRangeStart) / mScale).toInt()
        //大刻度 小刻度的指 根据 高度设置
        mSLineHeight = height / 4
        mLLineHeight = height / 2
        //遍历的时候从0 开始 到 10 一共 11个数
        val temp = mCountLine + 1
        //内容宽度 == 能够滑动的距离 == 大刻度宽+小刻度宽+间隔
        val sumLLine = temp / 10 + 1 // 10个数 两个大刻度 1，10
        val sumSLine = temp - sumLLine //总刻度数 - 大刻度数 = 小刻度数
        val sumSpace = temp - 1  // 10个数 9个空
        mContentWidth = sumLLine * mLLineWidth + sumSLine * mSLineWidth + sumSpace * mLineSpace
    }

    /*------------------------------------------滑动-------------------------------------*/


    /**
     * 手指拖拽内容滑动 + 根据速度惯性滑动
     */
    @SuppressLint("ClickableViewAccessibility")
    override fun onTouchEvent(event: MotionEvent): Boolean {
        mVelocityTracker.addMovement(event)
        val currX = event.x
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                if (!mScroller.isFinished) {
                    mScroller.abortAnimation()
                }
                mLastX = currX
            }
            MotionEvent.ACTION_MOVE -> {
                val distance = (mLastX - currX).toInt()
                scrollBy(distance, 0)
                mLastX = currX

            }
            MotionEvent.ACTION_UP -> {
                mVelocityTracker.computeCurrentVelocity(1000)
                // 获取横向速度
                val velocityX = mVelocityTracker.xVelocity.toInt()
                if (Math.abs(velocityX) > mMinimumVelocity) {
                    val startX = scrollX
                    //需要坐标轴知识
                    // 手指左滑  x轴正方向 值越来越大 正数
                    // 手指右滑  x轴负方向 值越来越小 负数
//                    val flingMaxX: Int = if (velocityX > 0) {
//                        //速度正数 手指右滑  x坐标减少
//                        startX - 100
//                    } else {
//                        //速度负数 手指左滑  x坐标增加
//                        startX + 100
//                    }
//                    Log.d("aaa", "滑动速度：${velocityX}   startX：${startX}  flingMaxX:${flingMaxX}")
                    /*
                     fling 参数解析：
                        startX：开始位置
                        minX-maxX：区间
                            根据速度计算x值 的范围在 minX maxX之间
                        velocityX 的影响
                            手指左滑 速度正数 scroller动画结果 从小到大 x轴正方向移动 值变大
                            手指右滑 速度负数 scroller动画结果 从大到小 x轴负方向移动 值变小
                        产生了一个问题：
                            期望效果 手指右滑 x轴正方向移动 值增加 变大
                            实际效果 手指右滑 速度负数 fling效果 x轴负方向移动 值变小
                            正好相反 所以速度取相反数 效果正好

                     */
                    mScroller.fling(
                        startX, 0, -velocityX, 0,
                        0, 10000, 0, 0
                    )
                    invalidate()
                } else {
                    //速度不够滑动 直接开启自动定位
                    startAutoPosition()
                }
                mVelocityTracker.clear()
            }
        }
        return super.onTouchEvent(event)
    }

    /**
     * 处理滑动边界
     */
    override fun scrollTo(x: Int, y: Int) {
        var resultX = x
        if (resultX <= 0) {
            resultX = 0
        } else if (resultX >= mContentWidth) {
            resultX = mContentWidth
        }
        super.scrollTo(resultX, y)
        //计算当前刻度
        calculateCurrScale()
    }

    /**
     * fling 后 惯性滑动
     */
    override fun computeScroll() {
        super.computeScroll()
        if (mScroller.computeScrollOffset()) {
            if (mAutoPosition) {
                //自动定位
                if (mScroller.isFinished) {
                    //自动定位滑动结束 关闭自动定位标记
                    mAutoPosition = false
                } else {
                    //执行滑动逻辑
                    scrollTo(mScroller.currX, 0)
                    invalidate()
                }
            } else {
                //惯性滑动
                if (mScroller.isFinished) {
                    //滑动结束 开启自动定位
                    startAutoPosition()
                } else {
                    //执行滑动逻辑
                    scrollTo(mScroller.currX, 0)
                    invalidate()
                }
            }

        }
    }

    /**
     * 开始自动定位
     */
    private fun startAutoPosition() {
        mAutoPosition = true
//        calculateCurrScale()
        val currX = scrollX
        val index = (mValue - mRangeStart).toBigDecimal()
            .divide(mScale.toBigDecimal(), 0, RoundingMode.HALF_UP).toInt()
        //计算结果分度值的x点位 resultX
        val resultX = getDrawnWidth(index)
        //  计算 滑动距离 负数内容向右 正数内容向左
        val resultDis = resultX - currX
        //知道滑动距离了 执行动画即可
        mScroller.startScroll(currX, 0, resultDis, 0)
        invalidate()
//        Log.d(
//            "calculateProgress",
//            "currX: $currX    mContentWidth: $mContentWidth    progressRatio: $progressRatio    " +
//                    "\nmeasuredValue: $measuredValue    positionValue: $positionValue      resultValue : ${positionValue.toFloat() + mRangeStart}" +
//                    "\n index:${index}  resultX: $resultX  resultDis:$resultDis"
//        )
    }

    /**
     * 计算当前刻度
     * 核心思路：当前滑动值scrollX 与 总滑动距离  计算比例
     * 滑动范围  与 尺子度量范围 相等 所以可以进行等比换算 求出当前刻度
     * scrollTo() 是内容滑动最终实现的位置 所以当前方法的唯一调用在scrollTo()
     */
    private fun calculateCurrScale() {
        //当前刻度 通过比例算
        val currX = scrollX
        //当前进度(currX) / 总进度(mContentWidth) == 进度百分比
        val progressRatio =
            currX.toBigDecimal().divide(mContentWidth.toBigDecimal(), 8, RoundingMode.HALF_UP)
        //测量范围 计算 尺子的测量数值范围
        val measuringRange = (mRangeEnd - mRangeStart).toBigDecimal()
        //根据进度百分比 求得 测量值
        val measuredValue = progressRatio.multiply(measuringRange)
        //以分度值为单位四舍五入 根据测量值找到定位值
        val decimalPoint = getScaleDecimalPoint()
        //定位值
        val positionValue = measuredValue.setScale(decimalPoint, RoundingMode.HALF_UP)
        mValue = positionValue.toFloat() + mRangeStart
        onValueChangeListener?.onChange(mValue)
    }


    fun setValue(value: Float) {
        if (value < mRangeStart || value > mRangeEnd) {
            throw RuntimeException()
        }
        mValue = value
        post {
            val positionValue = (value - mRangeStart).toBigDecimal()
            val index = positionValue.divide(mScale.toBigDecimal(), 0, RoundingMode.HALF_UP).toInt()
            val resultX = getDrawnWidth(index)
            scrollTo(resultX, 0)
            invalidate()
        }
    }

    fun getValue(): Float {
        return mValue
    }


    //获取分度值小数点位数
    private fun getScaleDecimalPoint(): Int {
        return when {
            mScale > 1 -> {
                0
            }
            mScale < 1 -> {
                val text = mScale.toString()
                val list = text.split(".")
                list[1].length
            }
            else -> {
                0
            }
        }

    }


    /*------------------------------------------绘制-------------------------------------*/
    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        for (i in 0..mCountLine) {
            mRect.left = mStartDrawX + getDrawnWidth(i)
            if (isVisibleArea(mRect.left)) {
                drawLine(i, canvas)
                drawText(i, canvas)
            }
        }
        drawBaseLine(canvas)
    }


    /**
     * 绘制刻度
     */
    private fun drawLine(i: Int, canvas: Canvas) {
        mRect.top = 0
        if (i % 10 == 0) {
            mRect.bottom = mLLineHeight
            mRect.right = mRect.left + mLLineWidth
            mPaint.color = mLLineColor
        } else {
            mRect.bottom = mSLineHeight
            mRect.right = mRect.left + mSLineWidth
            mPaint.color = mSLineColor
        }
        canvas.drawRect(mRect, mPaint)
    }

    private fun getDrawnWidth(i: Int): Int {
        var width = 0
        if (i == 0) {
            width + mLLineWidth
        } else {
            val lLineCount = i / 10 + 1
            val sLineCount = i + 1 - lLineCount
            width = lLineCount.times(mLLineWidth)
                .plus(sLineCount.times(mSLineWidth))
                .plus(i * mLineSpace)
        }
        return width
    }

    /**
     * 绘制刻度值
     * i == 0  第一个刻度，i == 1  第二个刻度
     */
    private fun drawText(i: Int, canvas: Canvas) {
        if (i % 10 == 0) {
            mPaint.color = mTextColor
            mPaint.textSize = mTextSize
//            val text = ((mRangeStart + i) * mScale).toInt().toString()
            val coefficient = i.toBigDecimal().multiply(mScale.toBigDecimal()).toFloat()
            val text = mRangeStart.plus(coefficient).toString()
            val textHeight = mPaint.fontSpacing
            val textWidth = mPaint.measureText(text)
            val x = mRect.left - textWidth / 2 + 2 //2 偏移量
            val y = mLLineHeight + mTextSpace + textHeight
            mPaint.isFakeBoldText = true
            canvas.drawText(
                text, x, y, mPaint
            )
            mPaint.isFakeBoldText = false
        }
    }

    /**
     * 绘制基准线
     */
    private fun drawBaseLine(canvas: Canvas) {
        mPaint.color = ContextCompat.getColor(context, android.R.color.holo_red_light)
        mRect.top = 0
        mRect.bottom = mLLineHeight
        mRect.left = scrollX + mStartDrawX
        mRect.right = mRect.left + mBLLineWidth
        canvas.drawRect(mRect, mPaint)
    }

    private fun isVisibleArea(x: Int): Boolean {
        //view的可见区域 = x轴坐标范围 = 滚动距离 + view的宽度
        val offset = 20 //偏移量
        val start = scrollX - offset
        val end = scrollX + measuredWidth + offset
        return x in start..end
    }

    override fun onDetachedFromWindow() {
        mVelocityTracker.recycle()
        super.onDetachedFromWindow()
    }

    interface OnValueChangeListener {
        fun onChange(value: Float)
    }
}